package
{
	import com.adobe.images.JPGEncoder;
	import com.quasimondo.bitmapdata.CameraBitmap;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Loader;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.external.ExternalInterface;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.net.SharedObject;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	import flash.utils.ByteArray;
	
	import jp.maaash.ObjectDetection.ObjectDetector;
	import jp.maaash.ObjectDetection.ObjectDetectorEvent;
	import jp.maaash.ObjectDetection.ObjectDetectorOptions;
	
	import mx.containers.Canvas;
	import mx.controls.Alert;
	import mx.core.UIComponent;
	import mx.events.CloseEvent;
	
	import ru.inspirit.surf.ASSURF;
	import ru.inspirit.surf.IPoint;
	import ru.inspirit.surf.SURFOptions;
	import ru.inspirit.surf_example.FlashSURFExample;
	import ru.inspirit.surf_example.MatchElement;
	import ru.inspirit.surf_example.MatchList;
	import ru.inspirit.surf_example.utils.QuasimondoImageProcessor;
	import ru.inspirit.surf_example.utils.RegionSelector;
	import ru.inspirit.surf_example.utils.SURFUtils;
	
	public class FaceDetector extends Canvas
	{
		
		public var detector    :ObjectDetector;
		public var options     :ObjectDetectorOptions;	
		public var view :Sprite;
		public var faceRectContainer :Sprite;
		public var camera:CameraBitmap;
		public var detectionMap:BitmapData;
		public var drawMatrix:Matrix;
		public var scaleFactor:int = 4;
		public var w:int = 640;
		public var h:int = 480;
		public var detectedFace:BitmapData;
		public var detectedRect:Rectangle = null;		
		public var So:SharedObject= SharedObject.getLocal("TempImage");
		[Bindable]
		public var ba:ByteArray;
		[Bindable]
		public var spriteContainer:UIComponent;
		[Bindable]
		public var enable:Boolean=false;
		[Bindable]
		public var bmp:Bitmap=null;
		
		public static const SCALE:Number = 1.5;
		public static const INVSCALE:Number = 1 / SCALE;
		
		public static const SCALE_MAT:Matrix = new Matrix(1/SCALE, 0, 0, 1/SCALE, 0, 0);
		
		protected var overlay:Shape;
		public var surf:ASSURF;
		public var surfOptions:SURFOptions;
		public var quasimondoProcessor:QuasimondoImageProcessor;
		public var buffer:BitmapData;
		public var autoCorrect:Boolean = false;
		public var matchList:MatchList;
		[Bindable]
		public var matched:Vector.<MatchElement>;
		
		public function FaceDetector()
		{
			init();
			initDetector();
			
			surfOptions = new SURFOptions(400, 400, 200, 0.001, true, 4, 4, 2);
			surf = new ASSURF(surfOptions);
			
			surf.pointMatchFactor = 0.3;
			surf.pointsThreshold = 0.001;
			
			buffer = new BitmapData(surfOptions.width, surfOptions.height, false, 0x00);
			buffer.lock();
			
			quasimondoProcessor = new QuasimondoImageProcessor(buffer.rect);
			
			matchList = new MatchList(surf);
			
			camera.addEventListener(Event.RENDER, render);
			
			autoCorrect = true;
			surf.imageProcessor = autoCorrect ? quasimondoProcessor : null;
		}
		
		protected function render( e:Event ) : void
		{
			var gfx:Graphics = overlay.graphics;
			
			buffer.draw(camera.bitmapData, SCALE_MAT);
			
			var ipts:Vector.<IPoint> = surf.getInterestPoints(buffer);
			gfx.clear();
			SURFUtils.drawIPoints(gfx, ipts, SCALE);
		}

		public function init():void{
			
			view = new Sprite();
			camera = new CameraBitmap( w, h, 15 );
			camera.addEventListener( Event.RENDER, cameraReadyHandler );
			view.addChild( new Bitmap( camera.bitmapData ) );
			
			overlay = new Shape();
			view.addChild(overlay);
			
			detectionMap = new BitmapData( w / scaleFactor, h / scaleFactor, false, 0 );
			drawMatrix = new Matrix( 1/ scaleFactor, 0, 0, 1 / scaleFactor );
			
			faceRectContainer = new Sprite();
			view.addChild( faceRectContainer);
			
			spriteContainer= new UIComponent();
			spriteContainer.addChild(view);
			
		}
		
		public function cameraReadyHandler( event:Event ):void
		{
			detectionMap.draw(camera.bitmapData,drawMatrix,null,"normal",null,true);
			detector.detect( detectionMap );
		}
		
		public function initDetector():void
		{
			detector = new ObjectDetector();
			
			var options:ObjectDetectorOptions = new ObjectDetectorOptions();
			options.min_size  = 30;
			detector.options = options;
			detector.addEventListener(ObjectDetectorEvent.DETECTION_COMPLETE, detectionHandler );
		}
		
		
		public function detectionHandler( e :ObjectDetectorEvent ):void
		{
			var g :Graphics = faceRectContainer.graphics;
			g.clear();
			if( e.rects ){
				g.lineStyle( 2 );	// black 2pix
				e.rects.forEach( function( r :Rectangle, idx :int, arr :Array ) :void {
					
					g.drawRect( r.x * scaleFactor/2, r.y * scaleFactor/2, 400, 400 );
					r.x = r.x * scaleFactor/2;
					r.y = r.y * scaleFactor/2;
					r.width = 400;
					r.height = 400;
					detectedRect = r;
					enable=true;
				});
			}else{
				detectedRect = null;
				enable=false;
			}
		}
		
		public function displayImage(event:Event):void {
			
			bmp= event.currentTarget.content as Bitmap;
			bmp.smoothing=true;
		}
		
		
		public function loadImage(imgSo:ByteArray):void{
			var imgLoader:Loader = new Loader();
			imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,displayImage);
			imgLoader.loadBytes(imgSo);
		}
		
		private function saveImage():void {
			
			So.data.image = ba;
			try {
				So.flush();
			} catch (error:Error) {
				trace("Error...Could not write SharedObject to disk\n");
			}
			
			loadImage(So.data.image);
			
		}
		public function recognition():void{
			
			var xmlURL:URLRequest = new URLRequest("http://localhost/identification-debug/services/getAllUsers.php");
			var xmlLoader:URLLoader = new URLLoader(xmlURL);
			xmlLoader.addEventListener(Event.COMPLETE, getUsersComplete);
			
		}
		
		private function retryId(event:CloseEvent) : void
		{
			var loc:String = ExternalInterface.call("window.location.href.toString");
			navigateToURL(new URLRequest(loc), "_self");
		}
			
		public function isRecognized():void{
			
			trace("karaba1===" + matched.length );
			
			if(matched.length == 1){
				
				
			}else{
	
				Alert.okLabel = "RETRY";
			
				Alert.show("IMAGE AUTHENTICATION FAILED","Authentication Failed", Alert.OK, this, retryId);
			}
	
			trace('FOUND POINTS: ' + surf.currentPointsCount + '\nPOINTS TO MATCH: ' + matchList.pointsCount);
			
			
		}
			
			
		public function extractFace( ):void
		{	
			var encoder:JPGEncoder = new JPGEncoder();
			
			var detectedByte:ByteArray = camera.bitmapData.getPixels(detectedRect);
			detectedByte.position = 0;
			
			detectedFace = new BitmapData( detectedRect.width, detectedRect.height, true );
			
			for( var i:uint=0; i<detectedRect.height ; i++ )
			{
				for( var j:uint=0; j<detectedRect.width; j++ )
				{
					detectedFace.setPixel( j, i, detectedByte.readUnsignedInt() );
				}
			}
			
			ba= encoder.encode(detectedFace);
			ba.position=0;
			saveImage();
			
		}
		public function getUsersComplete (event:Event):void{
			var numRows:int;
			var numCols:int;
			var i:int;
			var j:int;
			
			var userString:String = event.target.data;
			var array:Array = userString.split(",");
			for(i=0;i<array.length;i++){
				if(array[i]!=""){
					var imageLdr:Loader = new Loader();
					var myData:URLRequest = new URLRequest("http://localhost/identification-debug/services/getImages.php?Input="+array[i]);
					imageLdr.load(myData);
					imageLdr.contentLoaderInfo.addEventListener(Event.COMPLETE, loadImageDB, false, 0, true);
					
				}
			}
			
			
		}
		public function loadImageDB(evt:Event):void {
			var bitmapDB:Bitmap = evt.currentTarget.content;
			matchList.addBitmapAsMatch(bitmapDB.bitmapData);
			
			matched = matchList.getMatches();
		}
		
	}
}